﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xplang.run;
using xplang.abstractions;
using System.Diagnostics;

namespace xplang.expression
{
  [DebuggerDisplay("{variable}")]

  public abstract class ValueReference : Expression
  {

    public ValueReference(ClassRef resultType)
      : base(resultType)
    {
    }

    public abstract bool byRef();
  }

  public class LocalVariableReference : ValueReference
  {

    public LocalVariableReference(Variable variable, int index)
      : base(variable.type)
    {
      this.index = index;
      this.variable = variable;
    }

    public readonly int index;
    public readonly Variable variable;

    public override Value doIt(Value[] heap, ref FlowState state)
    {
      return heap[index];
    }

    public override bool byRef()
    {
      return variable.byRef();
    }
  }

  public class InternalAttributeReference : ValueReference
  {

    public InternalAttributeReference(Variable variable)
      : base(variable.type)
    {
      this.variable = variable;
    }

    public readonly Variable variable;

    public override Value doIt(Value[] heap, ref FlowState state)
    {
      return heap[0].Get(variable);
    }

    public override bool byRef()
    {
      return variable.byRef();
    }
  }

  public class ExternalAttributeReference : ValueReference
  {

    public ExternalAttributeReference(Expression _this, Variable variable)
      : base(variable.type)
    {
      this._this = _this;
      this.variable = variable;
    }

    public readonly Expression _this;
    public readonly Variable variable;

    public override Value doIt(Value[] heap, ref FlowState state)
    {
      Value _thisobj = _this.doIt(heap, ref state);
      if (state != FlowState.Normal)
        return null;
      return _thisobj.Get(variable);
    }

    public override bool byRef()
    {
      return variable.byRef();
    }
  }

  public class ContextObjectReference : ValueReference
  {

    public ContextObjectReference(Value obj)
      : base(obj.type)
    {
      this.obj = obj;
    }

    public readonly Value obj;

    public override Value doIt(Value[] heap, ref FlowState state)
    {
      return obj;
    }

    public override bool byRef()
    {
      return true;
    }
  }
}
